package com.motu.monstercity.server.game.logic;

import com.motu.monstercity.module.common.servermanager.ServerInfo;
import com.motu.monstercity.module.common.servermanager.ServerManager;
import com.motu.monstercity.protocol.Common.PBUserData;
import com.motu.monstercity.server.game.base.AllParam;
import com.motu.monstercity.server.game.base.CommonUtils;
import com.motu.monstercity.server.game.base.ProtoDataUtils;
import com.motu.monstercity.server.game.commondata.bag.ItemId;
import com.motu.monstercity.server.game.commondata.fight.*;
import com.motu.monstercity.server.game.commondata.iap.PrivilegeCardConstant;
import com.motu.monstercity.server.game.commondata.mail.MailConstant;
import com.motu.monstercity.server.game.commondata.maintask.MainTaskConstant;
import com.motu.monstercity.server.game.commondata.rank.RankConstant;
import com.motu.monstercity.server.game.commondata.rank.RankReward;
import com.motu.monstercity.server.game.commondata.skill.SkillConstant;
import com.motu.monstercity.server.game.commondata.system.SystemConstant;
import com.motu.monstercity.server.game.log.LogType;
import com.motu.monstercity.server.game.log.ThinkingDataManager;
import com.motu.monstercity.server.game.userdata.*;
import com.motu.vertx.module.utility.model.EntityManager;
import com.motu.vertx.module.utility.redis.RedisTools;
import com.motu.vertx.module.utility.threadpool.DBLogManager;
import com.motu.vertx.module.utility.toolset.TimeUtils;
import com.motu.vertx.module.utility.toolset.Tool;
import io.vertx.core.Future;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class FightManager extends FightUserData {
    private static Logger logger = LoggerFactory.getLogger(FightManager.class);

    // 初始化下发战斗副本模块的用户数据
    public static void loadInitFightUserData(PBUserData.Builder pbUserData, UserInfo userInfo) {
        long userId = userInfo.getId();
        UserStage userStage = getUserStage(userId);
        ProtoDataUtils.updatePBUserData(pbUserData, userStage, true);

        UserMonsterTideInfo userMonsterTideInfo = getUserMonsterTiedInfo(userId);
        if (userMonsterTideInfo != null) {
            ProtoDataUtils.updatePBUserData(pbUserData, userMonsterTideInfo, true);
        }

        UserSnatchInfo userSnatchInfo = getUserSnatchInfo(userId);
        ProtoDataUtils.updatePBUserData(pbUserData, userSnatchInfo, true);
    }


    // 主线关卡普通关卡的基础消耗金币的数量
    public static double takeStageBaseGold(Stage stage, int nodeNum) {
        int value = 10000;//
        try {
            if (nodeNum > 1) {
                value = AllParam.STAGE_NODE_ADD_NUM[nodeNum - 2];// 小节成长系数，表示第2/3/4/5/6/7/8小节的成长系数，每个成长系数均与基础值相乘/10000
            }
        } catch (Exception e) {}
        return stage.getForces() * value / 10000;
    }

    /**
     *  消耗率
     * @return
     */
    public static double takeStageConsumeRatio(UserInfo userInfo, Stage stage, UserPower userPower) {
        double aa = 18 * userPower.countCurrentEarn() + 15 * stage.getForces() + 4500;
        double bb = 35 * userPower.countCurrentEarn() + 14.5 * stage.getForces() + 4200;
        double ratio = aa / bb;// 0.75
        int privilegeCardAdd = IapManager.takePrivilegeValueByType(userInfo.getId(), "stage_num");// 特权卡可以减少关卡损坏率
        if (privilegeCardAdd > 0) {
            return ratio  - privilegeCardAdd / 100;// 0.75 - 0.05
        } else {
            return ratio;
        }
    }

    // 每个小节的实际消耗金币 = 基础消耗金币 * 消耗率
    public static long takeStageConsumeNum(UserInfo userInfo, Stage stage, UserPower userPower, int nodeNum) {
        double baseNum = takeStageBaseGold(stage, nodeNum);
        double ratio = takeStageConsumeRatio(userInfo, stage, userPower);
        double aa = baseNum * ratio;
        return (long) Math.floor(aa);
    }

    // 每个攻击节点可以获得的经验数量
    public static long takeStageRewardNum(Stage stage, int nodeNum) {
        double baseNum = takeStageBaseGold(stage, nodeNum);
        double aa = Math.pow(baseNum, 1.5) + 50;
        double bb = baseNum * 5 - 150;
        double cc = aa / bb * 10;
        return (long) Math.floor(cc);
    }

    // 一个关卡总的需要消耗多少金币
    public static long countStageTotalGold(UserInfo userInfo, Stage stage, UserPower userPower) {
        long total = 0L;
        for (int i=1; i<=stage.getNodeNum(); i++) {
            total += takeStageConsumeNum(userInfo, stage, userPower, i);
        }
        return total;
    }

    // 一个关卡总的获得多少奖励,每个小节一个数值
    public static JsonArray countStageReward(Stage stage) {
        JsonArray jsonArray = new JsonArray();
        for (int i=1; i<=stage.getNodeNum(); i++) {
            long value = takeStageRewardNum(stage, i);
            jsonArray.add(value);
        }
        return jsonArray;
    }

    /**
     * 金币鼓舞需要消耗的金币数量
     * @param stage
     * @param n 鼓舞次数
     * @return
     */
    public static long takeStageInspireGoldNum(Stage stage, int n) {
        return stage.getForces() *  2  * n * (n - 1);
    }

    // 判断该章节id 是否 该区域的最后一章节
    public static boolean isAreaEndMap(int mapId, int areaId) {
        StageArea stageArea = getStageArea(areaId);
        if (stageArea == null) {
            return false;
        }
        if (mapId == stageArea.getMapIdEnd()) {
            return true;
        } else {
            return false;
        }
    }

    // 鼓舞后的总战力
    public static long takeStagePowerInspire(long userId, UserStage userStage) {
        int add = 10000;
        if (userStage.getInspireNum() > 0) {
            add += AllParam.INSPIRE_RAITO[0] * userStage.getInspireNum();
        }
        if (userStage.getInspireItemNum() > 0) {
            add += AllParam.INSPIRE_RAITO[1] * userStage.getInspireItemNum();
        }
        return GameUser.countUserPower(userId, add);// 获取玩家的当前总战力
    }


    /**
     * 兽潮战斗
     * @param userMonsterTideInfo
     * @param userAffair bufff
     */
    public static void monsterTideFight(PBUserData.Builder pbUserData, UserInfo userInfo, UserPower userPower, UserMonsterTideInfo userMonsterTideInfo, UserAffair userAffair) {
        int monsterTideId = userMonsterTideInfo.getNextMonsterTideId();
        if (monsterTideId == 0) {
            return;
        }

        MonsterTideMain monsterTideMain = getMonsterTideMain(monsterTideId);
        if (monsterTideMain == null) {
            return;
        }
        boolean isSucc = false;
        int nextId = 0;// 下一场兽潮的id
        long userCurPower = userPower.getPower();// 当前战力
        if (userCurPower > monsterTideMain.getPower()) {
            isSucc = true;
            nextId = monsterTideId + 1;
            RewardManager.addReward(userInfo, CommonUtils.takeReawrdItemFromStr(monsterTideMain.getReward()), pbUserData, LogType.FIGHT_MONSTER_TIDE, monsterTideId);
            MainTaskManager.addTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_238, 1);
            RankActManager.addTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_238, 1);
            RankManager.updateRank(RankConstant.SERVER_RANK_MONSTER_TIDE, userInfo.getServerId(), userInfo.getId(), monsterTideId, "0");// 全量更新排行榜
            MainTaskManager.updateServerHonor(pbUserData, userInfo, MainTaskConstant.HONOR_TYPE_4, monsterTideId);// 更新全服成就进度
        } else {
            nextId = monsterTideId;//失败下一场不变
        }
        // 更新UserMonsterTideInfo
        long curTime = TimeUtils.getCurTime();
        userMonsterTideInfo.putLastMonsterTideId(monsterTideId);
        userMonsterTideInfo.putLastResult(isSucc ? 1: 0);
        userMonsterTideInfo.putLastTime(curTime);
        userMonsterTideInfo.putLastMyPower(userCurPower);

        MonsterTideMain monsterTideMainNext = getMonsterTideMain(nextId);
        if (monsterTideMainNext != null) {
            userMonsterTideInfo.putNextMonsterTideId(nextId);
            long nextTime = isSucc ? curTime + monsterTideMainNext.getDelayTimeSucc() : curTime + monsterTideMainNext.getDelayTimeFail();
            userMonsterTideInfo.putNextTime(nextTime);
            userMonsterTideInfo.putMinTime(nextTime);// 战斗的最小时间
        }
        if (monsterTideMain.isFinalStage()) {// 全部打完
            userMonsterTideInfo.putNextMonsterTideId(0);
            userMonsterTideInfo.putNextTime(0);
        }
        userMonsterTideInfo.update();
        ProtoDataUtils.updatePBUserData(pbUserData, userMonsterTideInfo);

        // buff 增加收益还是减少收益X 更新兽潮入侵的buff并计算此时的城市收益
        updateMonsterTideBuff(pbUserData, userInfo, userPower, monsterTideMain, userAffair, isSucc, curTime);

        MainTaskManager.addTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_64, 1);
        RankActManager.addTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_64, 1);

        // 上报数数
        ThinkingDataManager.pushUserStageFightEvent(userInfo, 2, monsterTideId, isSucc, userPower);
    }


    public static void updateMonsterTideBuff(PBUserData.Builder pbUserData, UserInfo userInfo, UserPower userPower, MonsterTideMain monsterTideMain, UserAffair userAffair, boolean isSucc, long curTime) {
        if (isSucc) {
            if (monsterTideMain.isFinalStage()) {// 打赢了最后一关
                userPower.updateEarnAddMonster(pbUserData, userInfo, AllParam.MONSTER_TIDE_BUFFER[2]);// 增加永久加成
                userAffair.putMonsterTideBuff(0);
                userAffair.putMonsterTideBuffValue(0);
            } else {
                long diffTime = curTime - userAffair.getMonsterTideBuffStime();//
                if (userAffair.getMonsterTideBuff() == 1 && diffTime < AllParam.MONSTER_TIDE_BUFFER_DURATION_TIME * TimeUtils.HOUR) {// 原来也是胜利,且buff未过期,则累加
                    int maxValue = AllParam.MONSTER_TIDE_BUFFER[0] * AllParam.MONSTER_TIDE_BUFFER_MAX;// 上限
                    int newValue = Math.min(userAffair.getMonsterTideBuffValue() + AllParam.MONSTER_TIDE_BUFFER[0], maxValue);
                    userAffair.putMonsterTideBuffValue(newValue);// 不能超过上限
                } else {
                    userAffair.putMonsterTideBuffValue(AllParam.MONSTER_TIDE_BUFFER[0]);// 5%
                }
                userAffair.putMonsterTideBuff(1);// 改成增加收益
            }
        } else {
            userAffair.putMonsterTideBuffValue(AllParam.MONSTER_TIDE_BUFFER[1]);
            userAffair.putMonsterTideBuff(2);// 改成减少收益
        }

        userAffair.putMonsterTideBuffStime(curTime);
        userAffair.update();
        ProtoDataUtils.updatePBUserData(pbUserData, userAffair);

        if (userAffair.getMonsterTideBuff() == 1) {// 增加的收益
            userPower.updateEarnAddMonster(pbUserData, userInfo, userAffair.getMonsterTideBuffValue());
        } else if (userAffair.getMonsterTideBuff() == 2) {// 减少的收益
            userPower.updateEarnAddMonster(pbUserData, userInfo, -userAffair.getMonsterTideBuffValue());
        }
    }

    // 判断物资争夺模块是否开启
    public static boolean checkSnatchMoudleOpen() {
        // todo
        return true;
    }

    // 按匹配规则,获取对手的userid
    public static long getMatchEnemy(UserInfo userInfo, int myRank, long lastUserId) {
        int rankType = RankConstant.SERVER_RANK_POWER;
        int serverId = userInfo.getServerId();
        long dateKey = 0;
        int min = Math.max(0, myRank - AllParam.SNATHC_MATCH_RANK_RANG);
        int max = myRank  + AllParam.SNATHC_MATCH_RANK_RANG;//
        String rankName = RankManager.getRankName(rankType, serverId, dateKey);
        JsonArray list = Future.await(RedisTools.getRankListByIndex(rankName, min, max, false));// 取战力排行榜的玩家列表
        List<Long> userIdList = new ArrayList<>();
        for (int i=0; i<list.size(); i++) {
            long uid = Long.parseLong(list.getString(i));
            if (uid != userInfo.getId() && uid != lastUserId) {// 排除掉自己和上次匹配到的玩家
                UserSnatchInfo userSnatchInfo = getUserSnatchInfo(uid);
                UserSnatchScore userSnatchScore = getUserSnatchScore(uid);
                if (userSnatchInfo.getIsProtect() == 0 && userSnatchScore.getScore() > 0) {
                    userIdList.add(uid);
                }
            }
        }
        if (userIdList.size() == 0) {// 不触发保护机制
            for (int i=0; i<list.size(); i++) {
                long uid = Long.parseLong(list.getString(i));
                if (uid != userInfo.getId() && uid != lastUserId) {// 排除掉自己和上次匹配到的玩家
                    UserSnatchInfo  userSnatchInfo = getUserSnatchInfo(uid);
                    userIdList.add(uid);
                }
            }
        }
        if (userIdList.size() > 0) {
            int rand = Tool.getIntRandom(userIdList.size());
            return userIdList.get(rand);
        } else {
            return 0L;
        }
    }

    /**
     * 生成对手的数据,下发给客户端
     * @param pbUserData
     * @param userId 对手的userid
     */
    public static void takeMatchEnemyData(PBUserData.Builder pbUserData, long userId) {
        UserInfo userInfo = GameUser.getUserInfo(userId);
        List<UserPartner> partnerList = PartnerManager.getUserPartnerList(userId);
        ProtoDataUtils.updatePBUserData(pbUserData, userInfo, true);
        for (UserPartner userPartner : partnerList) {
            ProtoDataUtils.updatePBUserData(pbUserData, userPartner, true);
        }
    }

    /**
     * 物资争夺金币鼓舞需要消耗的金币数量
     * @param num 鼓舞次数
     * @return 金币数=我方总都市收益/秒*2*n*(n+1)【n为鼓舞的次数】已鼓舞2次，这次是第3次鼓舞，则num传3
     */
    public static long takeSnatchInspireGoldNum(UserPower userPower, int num) {
        double earn = userPower.countCurrentEarn();// 我的总赚钱速度
        double total = earn * 2 * num * (num + 1);
        return (long)Math.ceil(total);
    }


    // 战斗结束更新我方的各种任务进度
    public static void handleUpdateMyTask(PBUserData.Builder pbUserData, UserInfo userInfo, int koNum, int failNum) {
        MainTaskManager.addTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_119, 1);// 挑战N场 更新主线任务,成就,日常任务的进度
        RankActManager.addTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_119, 1);
        MainTaskManager.addTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_27, 1);// 更新主线任务,成就,日常任务的进度
        RankActManager.addTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_27, 1);
        if (koNum > 0) {
            MainTaskManager.addTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_6, koNum);// 更新主线任务,成就,日常任务的进度
            RankActManager.addTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_6, koNum);
            MainTaskManager.addTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_120, koNum);// 更新主线任务,成就,日常任务的进度
            RankActManager.addTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_120, koNum);
        }
        if (failNum > 0) {
            MainTaskManager.addTaskProgress(pbUserData, userInfo, MainTaskConstant.TASK_TYPE_153, failNum);// 更新我的任务进度
        }
    }

    // 生成名人广播数据
    public static void createSnatchFame(UserInfo userInfo, long enemyId, int koNum) {
        if (koNum >= 10) {
            ServerSnatchFame serverSnatchFame = new ServerSnatchFame(userInfo, enemyId, koNum);// 写入名人广播
            serverSnatchFame.doCreate();
        }
    }

    // 物资争夺，获取对方当前的战力列表
    public static List<Long> getPowerList(long userIdTarget) {
        List<Long> targetList = new ArrayList<>();
        List<UserPartner> partnerListTarget = PartnerManager.getUserPartnerList(userIdTarget);
        UserPower userPower = GameUser.getUserPower(userIdTarget);
        for (UserPartner userPartner : partnerListTarget) {
            int skillAdd = SkillManager.getSkillMoudleAdd(userIdTarget, SkillConstant.EFFECT_TYPE_4, userPartner.getCharacterType());// 干员技能加成,秘书技能加成
            long powerTarget = GameUser.countPowerByPartner(userIdTarget, userPartner.getPartnerId(), userPartner, userPower, skillAdd);
            targetList.add(powerTarget);
        }
        return targetList;
    }

    // 物资争夺的鼓舞加成 1次加成2%，最多20次，最多返回4000，表示加成40%
    public static int countInspireValue(int inspireNum) {
        if (inspireNum >= AllParam.SNATCH_ISPIRE_MAX_NUM) {
            inspireNum = AllParam.SNATCH_ISPIRE_MAX_NUM;// 最多鼓舞20次
        }
        return  AllParam.SNATCH_ISPIRE_RAITO * inspireNum;
    }

    /**
     * 本次战斗，打败对方N名干员
     * @param myPowerList 我方的战力列表
     * @param targetList 对方的战力列表
     * @return
     */
    public static int countKoNum(List<Long> myPowerList, List<Long> targetList) {
        long myTotalPower = 0L;// 我方的总战力
        for (int i=0; i<myPowerList.size(); i++) {
            myTotalPower += myPowerList.get(i);
        }

        int koNum = 0;//
        for (int i=0; i<targetList.size();i++) {
            long powerTarget = targetList.get(i);
            if (myTotalPower > powerTarget) {
                koNum++;
                myTotalPower = myTotalPower - powerTarget;
            } else {
                break;
            }
        }
        return koNum;
    }

    /**
     * 本次战斗，我方被对方打败N名干员
     * @param myPowerList 我方的战力列表
     * @param targetList 对方的战力列表
     * @return
     */
    public static int countFailNum(List<Long> myPowerList, List<Long> targetList) {
        long totalTarget = 0L;// 对方的总战力
        for (int i=0; i<targetList.size();i++) {
            long powerTarget = targetList.get(i);
            totalTarget += powerTarget;
        }

        int failNum = 0;//
        for (int i=0; i<myPowerList.size();i++) {
            long myPartnerPower = myPowerList.get(i);// 我方干员的战力
            if (totalTarget > myPartnerPower) {
                failNum++;
                totalTarget = totalTarget - myPartnerPower;
            } else {
                break;
            }
        }

        return failNum;
    }

    /**
     * 更新物资争夺的上阵干员的数据战斗次数
     * @param pbUserData
     * @param type 0-匹配战，1-挑战券
     * @param fightNum 战斗次数
     */
    public static void updateSnatchPartnerFightNum(PBUserData.Builder pbUserData, List<UserSnatchPartner> userSnatchPartnerList, int type, int fightNum)  {
        for (UserSnatchPartner userSnatchPartner : userSnatchPartnerList) {
            if (type == 0) {//
                userSnatchPartner.addMatchFightNum(fightNum);
                if (userSnatchPartner.getMatchFightNum() == AllParam.SNATCH_MATCH_FIGHT_NUM_MAX) {// 打了3次,进入cd时间
                    userSnatchPartner.putMatchFightCdTime(TimeUtils.getCurTime());
                }
            } else if (type == 1) {
                userSnatchPartner.addChallengeNum(fightNum);
            }
            userSnatchPartner.update();
            ProtoDataUtils.updatePBUserData(pbUserData, userSnatchPartner);
        }
    }

    /**
     *  物资争夺每次战斗，获得的奖励，
     * @param pbUserData
     * @param userInfo
     * @param userSnatchInfo
     * @param koNum 击败的干员数量
     * @param multiple 倍数，如高级悬赏令=5倍，高级挑战券4倍等
     * @param logType 日志类型
     */
    public static void sendSnatchFightReward(PBUserData.Builder pbUserData, UserInfo userInfo, UserSnatchInfo userSnatchInfo, int koNum, int multiple, int logType) {
        if (koNum <= 0) {
            return;
        }

        // 获得中转站的扩建工具
        RewardManager.addReward(userInfo, ItemId.FIGHT_SNATCH_TRANSFER_ITEM, takeTransferItemNum(koNum) * multiple, pbUserData, logType, koNum);

        // 获得贸易币
        RewardManager.addReward(userInfo, new RewardItem(ItemId.FIGHT_SNATCH_MONEY, takeFightSnatchMoneyNum(koNum) * multiple, userSnatchInfo), pbUserData, logType, koNum);
    }



    // 获得的物资数量 击败干员数量 * 2 * 干员、秘书加成
    public static int getAddScore(int koNum) {
        if (koNum <= 0) {
            return 0;
        }
        int total = koNum * 2;
        return total;
    }

    // 对方被击败N名干员，就扣N分
    public static int getSubScore(int koNum) {
        if (koNum <= 0) {
            return 0;
        }
        return koNum;
    }

    // 获得中转站扩建工具的数量  击败的干员数量 / 2（向上取整）
    public static int takeTransferItemNum(int koNum) {
        double rate = 2;
        return (int) Math.ceil(koNum / rate);
    }

    // 获得的贸易币数量
    public static int takeFightSnatchMoneyNum(int koNum) {
        if (koNum <= 0) {
            return 0;
        }
        int total = 0;
        List<SnatchFightReward> list = new ArrayList<>();
        for (SnatchFightReward snatchFightReward : getSnatchFightRewardMap().values()) {
            list.add(snatchFightReward);
        }
        for (SnatchFightReward snatchFightReward : list) {
            int num = snatchFightReward.getKoNumMax() - snatchFightReward.getKoNumMin() + 1;// 这档击败的干员数量 1-5 这档要打败5个人
            if (koNum >= num) {
                total += snatchFightReward.getBaseNum() * num;
                koNum = koNum - num;
            } else {
                num = koNum;
                total += snatchFightReward.getBaseNum() * num;
                break;
            }

        }
        return total;
    }

    // 中转站的奖励数量
    public static long getSnatchTransferRewardNum(UserPower userPower, UserSnatchInfo userSnatchInfo, SnatchTransfer snatchTransfer, long curTime) {
        if (curTime <= userSnatchInfo.getTransferTime() || snatchTransfer == null) {
            return 0L;
        }

        double earn = userPower.countCurrentEarn();
        double total = earn * snatchTransfer.getAddition() / 10000;// 每秒的收益
        long diffTime = curTime - userSnatchInfo.getTransferTime();
        int isMaxLimit = IapManager.takePrivilegeValueByType(userSnatchInfo.getId(), "is_snatch");// 购买的特权卡是否有加交易站的储存时间上限
        if (isMaxLimit  >  0) {// 有购买加时间上限的特权
            diffTime = Math.min(diffTime, AllParam.SNATCH_TRANSFER_REWARD_LIMIT_PRIVILEGE);// 不能超过上限时间
        } else {
            diffTime = Math.min(diffTime, snatchTransfer.getMaxTime());// 不能超过上限时间
        }
        
        total = total * diffTime;
        return (long)Math.floor(total);
    }

    // 判断物资争夺榜单是否结束,可以领取榜单奖励
    public static boolean isSnathcRankClose(long dateKey) {
        long curTime = TimeUtils.getCurTime();
        if (curTime - dateKey > TimeUtils.WEEK - TimeUtils.MINUTE * 30) {// 周日的23:30分结束
            return true;// 该榜单已结束,可以领取奖励
        } else {
            return false;
        }
    }

    // 判断当前是否物资争夺榜 的冲榜时间, 冲榜时间内才可以战斗，悬赏，追击，挑战
    public static boolean isSnatchRankIng(long curTime) {
        long dateKey = TimeUtils.getWeekOneTime(1, 0);// 周一的0点0分
        if (curTime > dateKey && (curTime - dateKey) <= (TimeUtils.WEEK - AllParam.SNATCH_RANK_LIMIT_TIME)) {// 周日的23:30分结束
            return true;
        } else {
            return false;
        }
    }

    // 设置物资争夺排行榜的过期时间
    public static void closeSnatchRank() throws Exception {
        try {
            int rankType = RankConstant.SERVER_RANK_SNATCH;
            String dateKey = RankManager.getDateKey(rankType);
            logger.info("###closeSnatchRankReward dateKey:" + dateKey);
            ConcurrentHashMap<Integer, ServerInfo> serverList= ServerManager.getServerList();// 获取所有的服务器
            for (ServerInfo serverInfo : serverList.values()) {
                String rankKey = RankManager.getRankName(rankType, serverInfo.getServerId(), dateKey);
                RedisTools.expire(rankKey, TimeUtils.DAY * 15);// 设置15天后过期
            }
        } catch (Exception e){
            String errMsg = Tool.getException(e);
            logger.error("###closeSnatchRankReward error:" + errMsg);
			DBLogManager.addServerCrashLog(999999, errMsg);
        }
    }

    // 给玩家发放物资争夺的榜单奖励邮件
    public static void sendSnatchRankRewardMail(UserInfo userInfo) {
        long userId = userInfo.getId();
        UserSnatchInfo userSnatchInfo = FightManager.getUserSnatchInfo(userId);
        long dateKey = userSnatchInfo.getDateKey();
        if (dateKey == 0 || !FightManager.isSnathcRankClose(dateKey)) {
            return;//  冲榜未结束
        }
        int myRank = RankManager.getMyRank(RankConstant.SERVER_RANK_SNATCH, userInfo.getServerId(), userId, TimeUtils.getDayStr(dateKey));
        RankReward rankReward = RankManager.getRankReward(RankConstant.SERVER_RANK_SNATCH, myRank);
        if (rankReward != null) {
            List<RewardItem> rewardItemList = CommonUtils.takeReawrdItemFromStr(rankReward.getReward());// 奖励
            MailManager.sendSystemMailReplaceContent(userId, MailConstant.SNATCH_RANK_REWARD_TITLE, MailConstant.SNATCH_RANK_REWARD_CONTENT, rewardItemList, LogType.FIGHT_SNATCH_RANK_REWARD, myRank);
        }
        userSnatchInfo.putDateKey(0);
        userSnatchInfo.update();// 更新领奖状态
    }

    //物资争夺 生成匹配战战斗的战报
    public static void createSnatchRecord (long userId, UserInfo enemyUserInfo, int koNum, int subNum) {
        JsonArray jsonArray = EntityManager.getEntityKeyList(UserPartner.class, userId);// 我的干员数量
        UserSnatchRecord userSnatchRecord = new UserSnatchRecord();
        userSnatchRecord.putUserId(userId);
        userSnatchRecord.putEnemyId(enemyUserInfo.getId());
        userSnatchRecord.putUserName(enemyUserInfo.getUserName());
        userSnatchRecord.putLevel(enemyUserInfo.getLevel());
        userSnatchRecord.putKoNum(koNum);
        userSnatchRecord.putIsKoAll(koNum >= jsonArray.size() ? 1 : 0);
        userSnatchRecord.putSubNum(subNum);
        userSnatchRecord.putAddTime(TimeUtils.getCurTime());
        userSnatchRecord.doCreate();
    }

    // 物资争夺的挑战，悬赏追击，生成仇人记录
    public static void createSnatchEnemy (long userId, UserInfo enemyUserInfo, int koNum, int subNum) {
        JsonArray jsonArray = EntityManager.getEntityKeyList(UserPartner.class, userId);// 我的干员数量
        UserSnatchEnemy userSnatchEnemy = new UserSnatchEnemy();
        userSnatchEnemy.putUserId(userId);
        userSnatchEnemy.putEnemyId(enemyUserInfo.getId());
        userSnatchEnemy.putUserName(enemyUserInfo.getUserName());
        userSnatchEnemy.putLevel(enemyUserInfo.getLevel());
        userSnatchEnemy.putKoNum(koNum);
        userSnatchEnemy.putIsKoAll(koNum >= jsonArray.size() ? 1 : 0);
        userSnatchEnemy.putSubNum(subNum);
        userSnatchEnemy.putAddTime(TimeUtils.getCurTime());
        userSnatchEnemy.doCreate();
    }

    //  获取我的物资排名
    public static int getMyRankSnatch(UserInfo userInfo, UserSnatchScore userSnatchScore) {
        if (userSnatchScore.getScore() > 0) {
            int rankType = RankConstant.SERVER_RANK_SNATCH;
            String dateKey = RankManager.getDateKey(rankType);
            int myRank = RankManager.getMyRank(rankType, userInfo.getServerId(), userInfo.getId(), dateKey);
            return myRank;
        } else {
            return 0;//未上榜
        }
    }

    // 统计boss关卡实际的战力要求, 干员技能,秘书技能会减少
    public static long countPowerStageForces(long userId, Stage stage) {
        int skillAdd = SkillManager.getSkillMoudleAdd(userId, SkillConstant.EFFECT_TYPE_10, 0);
        return CommonUtils.countPerValue(stage.getForces(), -skillAdd);
    }

    public static int getStageKey(int mapId, int stageId) {
        return mapId * 100 + stageId;
    }

    // 添加本服的悬赏战斗数据
    public static void addServerSanchOfferFightInfo(ServerSnatchOffer serverSnatchOffer, UserInfo userInfo, int koNum) {
        JsonArray jsonArray = new JsonArray();
        if (!Tool.isEmpty(serverSnatchOffer.getFighterInfo())) {
            jsonArray = new JsonArray(serverSnatchOffer.getFighterInfo());
        }
        JsonObject infoObj = new JsonObject();
        infoObj.put("userName", userInfo.getUserName());
        infoObj.put("icon", userInfo.getIcon());
        infoObj.put("koNum", koNum);
        jsonArray.add(infoObj);
        serverSnatchOffer.putFighterInfo(jsonArray.toString());
    }

    // 创建本服悬赏的数据
    public static ServerSnatchOffer createServerSnatchOffer(UserInfo userInfo, UserInfo userInfoTarget, boolean isPro, ServerSnatchOffer serverSnatchOffer) {
        int type = isPro ? 2 : 1;// 高级悬赏type =2,普通悬赏type =1
        if (serverSnatchOffer == null) {
            serverSnatchOffer = new ServerSnatchOffer(userInfo, userInfoTarget, type);
            serverSnatchOffer.doCreate();
        } else {
            serverSnatchOffer.putServerId(userInfo.getServerId());
            serverSnatchOffer.putUserId(userInfoTarget.getId());
            serverSnatchOffer.putUserName(userInfoTarget.getUserName());
            UserPower userPowerTarget = GameUser.getUserPower(userInfoTarget.getId());
            serverSnatchOffer.putPower(userPowerTarget.getPower());
            serverSnatchOffer.putPartner(PartnerManager.createPartnerPhoto(userInfoTarget.getId(), userPowerTarget));
            serverSnatchOffer.putIcon(userInfoTarget.getIcon());
            serverSnatchOffer.putType(type);
            serverSnatchOffer.putUserIdPublish(userInfo.getId());
            long curTime = TimeUtils.getCurTime();
            serverSnatchOffer.putPublishTime(curTime);
            serverSnatchOffer.putCompleteTime(curTime + AllParam.SNATCH_OFFER_DURATION_TIME);
            serverSnatchOffer.putFighter("");
            serverSnatchOffer.putFighterInfo("");
            serverSnatchOffer.putKoNum(0);
            serverSnatchOffer.putIsSendReward(0);
            serverSnatchOffer.update();
        }
        return serverSnatchOffer;
    }

    /**
     * 挑战成功给玩家上阵的干员增加战力加成
     * @param pbUserData
     * @param userInfo
     * @param userPower
     * @param partnerList
     * @param koNum
     * @param rewardMul 普通挑战券加100  高级挑战券则增加100*5
     */
    public static void updateUserPartnerPower(PBUserData.Builder pbUserData, UserInfo userInfo, UserPower userPower, List<UserPartner> partnerList, int koNum, int rewardMul) {
        if (koNum <= 0) {
            return;
        }
        // 英雄实力加成 = 玩家都市等级 * 击败的英雄数量 使用高级挑战券则增加100*5 = 500点固定实力
        long addValue = userInfo.getLevel() * koNum * rewardMul;
        long addValueTotal = 0L;// 玩家总的战力
        for (UserPartner userPartner : partnerList) {
            addValueTotal += userPartner.updateSnatchAdd(pbUserData, userInfo, userPower, addValue);
            userPartner.update();
            ProtoDataUtils.updatePBUserData(pbUserData, userPartner);
        }
        if (addValueTotal > 0) {
            userPower.handlePowerChange(pbUserData, userInfo, userPower.getPower() + addValueTotal);// 玩家的基础战力增加
        }
    }

    // 设置物资争夺快速战斗的队伍配置
    public static void setSnatchTeam(PBUserData.Builder pbUserData, UserInfo userInfo, int teamId, JsonArray partnerList, int isInspire) {
        long userId = userInfo.getId();
        UserSnatchTeam userSnatchTeam = FightManager.getUserSnatchTeam(userId, teamId);
        if (userSnatchTeam == null) {
            userSnatchTeam = new UserSnatchTeam();
            userSnatchTeam.putUserId(userId);
            userSnatchTeam.putTeamId(teamId);
            userSnatchTeam.putPartner(partnerList.toString());
            userSnatchTeam.putIsInspire(isInspire);
            userSnatchTeam.doCreate();
            ProtoDataUtils.updatePBUserData(pbUserData, userSnatchTeam, true);
        } else {
            userSnatchTeam.putPartner(partnerList.toString());
            userSnatchTeam.putIsInspire(isInspire);
            userSnatchTeam.update();
            ProtoDataUtils.updatePBUserData(pbUserData, userSnatchTeam);
        }
    }

    // 最多可以战斗几次,取战斗第三的最小值
    public static int getMaxFightNum(List<UserSnatchPartner> userSnatchPartnerList) {
        int maxNum = AllParam.SNATCH_MATCH_FIGHT_NUM_MAX;// 最多3次
        for (UserSnatchPartner userSnatchPartner : userSnatchPartnerList) {
            int num = AllParam.SNATCH_MATCH_FIGHT_NUM_MAX - userSnatchPartner.getMatchFightNum();// 剩余的战斗次数
            if (num < maxNum) {
                maxNum = num;
            }
        }
        return maxNum;
    }

    // 解锁围墙卫兵挂机奖励功能
    public static void unlockStageGuardReward(PBUserData.Builder pbUserData, UserInfo userInfo, UserStage userStage) {
        UserAffair userAffair = GameUser.getUserAffair(userInfo.getId());
        SystemManager.checkSystemModelOpen(pbUserData, userInfo, userAffair, userStage, SystemConstant.SYSTEM_MODULE_ID_STAGE_GUARD_REWARD);
    }

    /**
     * 结算卫兵的挂机奖励
     * @param userInfo
     * @param userStage
     * @return false 无更新
     */
    public static boolean closeStageGuardReward(UserInfo userInfo, UserStage userStage) {
        Stage stage = userStage.takeCompleteStage();
        if (stage == null) {
            return false;
        }
        long curTime = TimeUtils.getCurTime();// 当前时间
        long lastTime = userStage.getGuardRewardTime();
        long lastTimeRandom = userStage.getGuardRewardRandomTime();
        if (curTime - lastTime <= TimeUtils.MINUTE) {// 不足1分钟
            return false;
        }

        //System.out.println("max:" + getGuardTimeMax(userInfo.getId()));
        long timeMax = getGuardTimeMax(userInfo.getId()) - userStage.getGuardCloseTime();// 本次可结算奖励的时间上限, 如上次已经结算了1小时，则本次最多8小时
        if (timeMax <= 0) {
            return false;
        }

        long diffTime = Math.min(curTime - lastTime, timeMax);// 普通奖励的时长
        long diffTimeRandom = Math.min(curTime - lastTimeRandom, timeMax);//随机奖励的时长
        //System.out.println("diffTime:" + diffTime + " diffTimeRandom:" + diffTimeRandom + " timeMax:" + timeMax + " gold:" + stage.getGuardGoldNum() + " exp:" + stage.getGuardExpNum() + " repu:" + stage.getGuardCityExpNum());

        // 普通奖励的份数，1分钟1份
        List<RewardItem> rewardItemList = new ArrayList<>();
        int rewardNum = (int) Math.floor((double)(diffTime / TimeUtils.MINUTE));
        //System.out.println("rewardNum:" + rewardNum);
        rewardItemList.add(new RewardItem(ItemId.GOLD, stage.getGuardGoldNum() * rewardNum));
        rewardItemList.add(new RewardItem(ItemId.PARTNER_EXP, stage.getGuardExpNum() * rewardNum));
        rewardItemList.add(new RewardItem(ItemId.USER_REPU, stage.getGuardCityExpNum() * rewardNum));
        userStage.addGuardRewardTime(rewardNum * TimeUtils.MINUTE);
        //System.out.println("普通奖励份数:" + rewardNum);
        //CommonUtils.printRewwardItemList(rewardItemList);

        // 随机奖励，5分钟1份
        long tmp = TimeUtils.MINUTE * AllParam.GUARD_BOX_TIME;//
        int randomNum = (int) Math.floor((double)(diffTimeRandom / tmp));  // 几个随机奖励
        List<RewardItem> rewardItemListRandom = getGuardRandomReward(userStage, randomNum);
        userStage.addGuardRewardRandomTime(randomNum * tmp);
        //System.out.println("随机奖励份数:" + randomNum);
        //CommonUtils.printRewwardItemList(rewardItemListRandom);

        // 合并奖励
        List<RewardItem> totalReward = MailManager.takeRewardItem(userStage.getGuardReward());// 原来未领取的奖励
        CommonUtils.mergeItemList(totalReward, rewardItemList);
        CommonUtils.mergeItemList(totalReward, rewardItemListRandom);
        //System.out.println("总的奖励：");
        //CommonUtils.printRewwardItemList(totalReward);
        String rewardStr = MailManager.getMailItem(CommonUtils.mergeItemList(totalReward));
        userStage.putGuardReward(rewardStr);

        userStage.addGuardCloseTime(rewardNum * TimeUtils.MINUTE);

        return true;
    }


    /**
     * 获取围墙挂机，城防巡逻的随机宝箱奖励
     * @param userStage
     * @param randomNum  随机几次，5分钟1次
     * @return
     */
    public static List<RewardItem> getGuardRandomReward(UserStage userStage, int randomNum) {
        List<RewardItem> result = new ArrayList<>();
        Stage stage = userStage.takeCompleteStage();
        if (stage == null || randomNum < 1) {
            return result;
        }
        List<StageGuardItem> list = FightManager.getStageGuardItemList(stage.getGuardGroupId());// 随机的池子
        int[] rates = new int[list.size()];
        for (int i=0; i< list.size(); i++)  {
            rates[i] = list.get(i).getRate();
        }
        for (int i=0;i<randomNum;i++) {
            StageGuardItem stageGuardItem = list.get(Tool.getWeightIndex(rates));// 随机到的奖励
            if (stageGuardItem != null) {
                result.add(new RewardItem(stageGuardItem.getItemId(), stageGuardItem.getItemNum()));
            }
        }
        return result;
    }

    // 卫兵挂机奖励的时间上限
    public static long getGuardTimeMax(long userId) {
        int max = AllParam.GUARD_TIME_LIMIT;//单位分钟
        int pricardAdd = IapManager.takePrivilegeValueByType(userId, PrivilegeCardConstant.TYPE_GUARD_TIME_ADD);// 特权卡增加快速领取的次数
        int total = (max + pricardAdd) * TimeUtils.MINUTE;// 转成秒
        return total;
    }

    // 卫兵挂机奖励的快速领取次数上限
    public static long getGuardQuickMaxNum(long userId) {
        int max = AllParam.GUARD_QUICK_NUM;
        int pricardAdd = IapManager.takePrivilegeValueByType(userId, PrivilegeCardConstant.TYPE_GUARD_QUICK_NUM);// 特权卡增加快速领取的次数
        return max + pricardAdd;
    }

    // 快速领取卫兵挂机奖励需要消耗的钻石数量
    public static int getGuardQuickCostNum(UserStage userStage) {
        int num = userStage.getGuardQuickNum();
        int len = AllParam.GUARD_QUICK_COST.length;
        if (num >= len) {
            return AllParam.GUARD_QUICK_COST[len - 1];
        } else {
            return AllParam.GUARD_QUICK_COST[num];
        }
    }

    /**
     * 计算战斗鼓舞，总的需要消耗多少金币
     * @param userPower
     * @param curNum 当前已鼓舞的次数
     * @param totalNum 本次鼓舞的总次数，客户端上传
     * @return
     */

    public static long countSnatchInspire(UserPower userPower, int curNum, int totalNum) {
        long goldNumTotal = 0L;
        for (int i=0; i<totalNum; i++) {
            int nextNum = curNum + 1 + i;
            long goldNum = FightManager.takeSnatchInspireGoldNum(userPower, nextNum);//  【n为鼓舞的次数】已鼓舞2次，这次是第3次鼓舞，则num传3
            goldNumTotal += goldNum;
        }
        return goldNumTotal;
    }

    //  解锁兽潮id
    public static UserMonsterTideInfo unlockMonsterTide(long userId) {
        return (UserMonsterTideInfo) EntityManager.getUniqueEntity(UserMonsterTideInfo.class, userId);//
    }
}
